import { CanvasMode, HorizontalAlign, VerticalAlign, StretchDirection, EraserMode, EraserShapeMode } from './enums';
import { InkSettings } from './inksetting';
import { Stroke } from './stroke';
import { ImageItem } from './imageitem';
import { Rect } from '../geometry/rect';
import { Point, StrokePoint } from '../geometry/point';
import { InkProcessor } from './inkprocessor';
import { EventBase } from '../eventbase';
import { HtmlTextRender } from './htmltextrender';
import { ImageRender } from './imagerender';
import { EventNames } from './eventnames';
import { UndoItem } from './undoitem';
import { EraserProcessor } from './eraserprocessor';
import { Size } from '../geometry/size';

export class InnerCanvas extends EventBase {
    //#region 私有成员
    /**当前Canvas实例 */
    private _canvas: HTMLCanvasElement;
    /**画板初始宽度 */
    private _initWidth: number;
    /**画板初始高度 */
    private _initHeight: number;
    /**撤销线条队列 */
    private _uodoItems: UndoItem[] = [];
    /**ink操作器 */
    private _inkProcessor: InkProcessor;
    /**橡皮擦处理器 */
    private _eraserProcessor: EraserProcessor;
    /**图片呈现器 */
    private _imageRender: ImageRender;
    /**
     * html呈现器
     */
    private _htmlTextRender: HtmlTextRender;
    /**当前画板的模式 */
    private _mode: CanvasMode = CanvasMode.None;
    /**当前画板的线条粗细值 */
    private _strokeWidth: number = InkSettings.DefaultStrokeWidth;
    /**当前画板的线条颜色值 */
    private _strokeColor: string = InkSettings.DefaultStrokeColor;
    /**当前画板的背景色 */
    private _backgroundColor: string = InkSettings.DefaultBackgroundColor;
    /**当前线条集合 */
    private _strokes: Stroke[] = [];
    /**元素集合 */
    private _elements = [];
    /**底图或html内容水平对齐方式 */
    private  _horizontalAlign = HorizontalAlign.Left;
    /**底图或html内容垂直对齐方式 */
    private _verticalAlign = VerticalAlign.Top;
    /**是否自动处理图片拉伸 */
    private _autoStrech: boolean = true;
    /**图片自定义拉伸方向(autoStrech)为false时此设置有效
     * ,如果设置的图片为多张则设置为StretchDirection.Height不会起作用
     * ,如果设置的图片为多张verticalAlign设置也将不会起作用,只允许顶对齐
     */
    private _stretchDirection = StretchDirection.None;
    /**鼠标或触控按下处理 */
    private onMouseOrTouchStart = (event: MouseEvent | TouchEvent) => { this.mouseOrTouchStartEvent(event); };
    //#endregion

    //#region 构造函数
    /**
     * 构造函数
     * @param caller Canvas实例
     * @param canvas 对应画板
     */
    constructor(canvas: HTMLCanvasElement) {
        super();
        this._canvas = canvas;
        // 设置初始画板的款高度
        this._initWidth = this.parentWidth;
        this._initHeight = this.parentWidth;
        this.width = this._initWidth;
        this.height = this._initHeight;
        // 图片呈现器
        this._imageRender = new ImageRender(() => new Rect(0, 0, this.parentWidth, this.parentHeight),
        this._horizontalAlign, this._verticalAlign, this._autoStrech, this._stretchDirection);
        // html呈现器
        this._htmlTextRender = new HtmlTextRender(() => new Rect(0, 0, this.parentWidth, this.parentHeight),
        this._horizontalAlign, this._verticalAlign);
        // 实例化书写处理器
        this._inkProcessor = new InkProcessor(this, this._canvas);
        this._inkProcessor.addListener(EventNames.gesturedPointEventName, (source) => {
            this.publishEvent(EventNames.gesturedPointEventName, source);
        });
        this._inkProcessor.addListener(EventNames.newStrokeEventName, (source) => {
            this.publishEvent(EventNames.newStrokeEventName, source);
        });
        // 实例化橡皮擦处理器
        this._eraserProcessor = new EraserProcessor(this, this._canvas);
        this._eraserProcessor.addListener(EventNames.strokeDeletedEventName, (source) => {
            this.publishEvent(EventNames.strokeDeletedEventName, source);
        });
        // 检查事件订阅
        this.checkCanvasEvent();
        // 订阅窗口调整事件
        window.addEventListener('resize', () => {
            this.updateLayout();
        });
    }
    //#endregion

    //#region get/set属性定义
    /**获取绘制上下文 */
    public get context(): CanvasRenderingContext2D {
        return this._canvas.getContext('2d') as CanvasRenderingContext2D;
    }
    /**
     * 获取或设置当前画板的模式
     */
    public get mode() {
        return this._mode;
    }
    public set mode(value: number) {
        if (this._mode !== value) {
            this._mode = value;
            this.checkCanvasEvent();
        }
    }
    /**
     * 当前画板的线条粗细值
     */
    public get strokeWidth() {
        return this._strokeWidth;
    }
    public set strokeWidth(value: number) {
        if (this._strokeWidth !== value) {
            this._strokeWidth = value;
        }
    }
    /**
     * 当前画板的线条颜色值
     */
    public get strokeColor() {
        return this._strokeColor;
    }
    public set strokeColor(value: string) {
        if (this._strokeColor !== value) {
            this._strokeColor = value;
        }
    }
        /**
     * 当前画板的线条颜色值（设置此属性将导致重绘）
     */
    public get backgroundColor() {
        return this._backgroundColor;
    }
    public set backgroundColor(value: string) {
        if (this._backgroundColor !== value) {
            this._backgroundColor = value;
            // 重新绘制
            this.reDraw();
        }
    }
    /**
     * 获取或设置当前画板宽度
     */
    public get width() {
        return this._canvas ? this._canvas.width : 0;
    }
    public set width(value: number) {
        if (this._canvas) {
            this._canvas.width = value;
        }
    }
    /**获取当前画板高度 */
    public get height() {
        return this._canvas ? this._canvas.height : 0;
    }
    public set height(value: number) {
        if (this._canvas) {
            this._canvas.height = value;
        }
    }
    /**获取当前画板的父元素 */
    public get parentElement() {
        return this._canvas ? this._canvas.parentElement : null;
    }
    /**获取当前画板的父元素内部呈现宽度 */
    public get parentWidth() {
        const parentElement = this._canvas.parentElement;
        return parentElement ? parentElement.clientWidth : 0;
    }
    /**获取当前画板的父元素内部呈现高度 */
    public get parentHeight() {
        const parentElement = this._canvas.parentElement;
        return parentElement ? parentElement.clientHeight : 0;
    }
    /**
     * 获取或设置橡皮擦擦除模式
     */
    public get eraserMode() {
        return this._eraserProcessor.eraserMode;
    }
    public set eraserMode(value: EraserMode) {
        this._eraserProcessor.eraserMode = value;
    }
    /**
     * 获取或设置橡皮形状模式
     */
    public get eraserShapeMode() {
        return this._eraserProcessor.eraserShapeMode;
    }
    public set eraserShapeMode(value: EraserShapeMode) {
        this._eraserProcessor.eraserShapeMode = value;
    }
    /**
     * 获取或设置橡皮形状宽度
     */
    public get eraserWidth() {
        return this._eraserProcessor.eraserWidth;
    }
    public set eraserWidth(value: number) {
        this._eraserProcessor.eraserWidth = value;
    }
    /**获取或设置当前线条集合（设置此属性将导致重绘） */
    public get strokes() {
        return this._strokes;
    }
    public set strokes(value: Stroke[]) {
        if (this._strokes !== value) {
            this._strokes = value || [];
            // 重新绘制
            this.reDraw();
        }
    }
    /**获取或设置元素集合 */
    public elements() {
        return this._elements;
    }
    /**获取底图图片x方向缩放比例 */
    public get imageScaleX() {
        return this._imageRender.imageScaleX;
    }
    /**获取底图图片y方向缩放比例 */
    public get imageScaleY() {
        return this._imageRender.imageScaleY;
    }
    /**获取或设置要显示的图片地址集合（设置此属性将导致重绘） */
    public get imageUrls() {
         return this._imageRender.imageUrls;
    }
    public set imageUrls(value: string[]) {
        if (value !== this._imageRender.imageUrls) {
            this._imageRender.imageUrls = value || [];
            this._imageRender.loadImagesAsync(() => {
                // 清除滚动位置
                this.scrollVerticalOffset = 0;
                this.scrollHorizontalOffset = 0;
                
                // 重新绘制
                this.reDraw();
                
                //事件通知
                const eventArgs = {images: this._imageRender.images, errorImages: this._imageRender.errorImages};
                this.publishEvent(EventNames.imageLoadedEventName, eventArgs);
            });
        }
    }
    /**获取或设置要显示的html内容（设置此属性将导致重绘） */
    public get html(): string {
        return this._htmlTextRender.html;
    }
    public set html(value: string) {
        if (value !== this._htmlTextRender.html) {
            this._htmlTextRender.html = value;
            this._htmlTextRender.loadHtmlAsync(() => {
                // 清除滚动位置
                this.scrollVerticalOffset = 0;
                this.scrollHorizontalOffset = 0;

                // 重新绘制
                this.reDraw(); 

                //事件通知
                const eventArgs = {success: !this._htmlTextRender.error};
                this.publishEvent(EventNames.imageLoadedEventName, eventArgs);
             });
        }
    }
    /**获取或设置画板底图或显示的html内容的水平对齐方式，默认：左对齐 */
    public get horizontalAlign() {
        return this._horizontalAlign;
    }
    public set horizontalAlign(value: HorizontalAlign) {
        if (this._horizontalAlign !== value) {
            this._horizontalAlign = value;
            this._imageRender.horizontalAlign = value;
            this._htmlTextRender.horizontalAlign = value;
        }
    }
    /**获取或设置画板底图或显示的html内容的垂直对齐方式，默认：顶对齐 */
    public get verticalAlign() {
        return this._verticalAlign;
    }
    public set verticalAlign(value: VerticalAlign) {
        if (this._verticalAlign !== value) {
            this._verticalAlign = value;
            this._imageRender.verticalAlign = value;
            this._htmlTextRender.verticalAlign = value;
        }
    }
    /**获取或设置是否自动处理图片拉伸 */
    public get autoStrech() {
        return this._autoStrech;
    }
    public set autoStrech(value: boolean) {
        if (this._autoStrech !== value) {
            this._autoStrech = value;
            this._imageRender.autoStrech = value;
        }
    }
    /**获取或设置图片自定义拉伸方向(autoStrech)为false时此设置有效
     * ,如果设置的图片为多张则设置为StretchDirection.Height不会起作用
     * ,如果设置的图片为多张verticalAlign设置也将不会起作用,只允许顶对齐
     */
    public get stretchDirection() {
        return this._stretchDirection;
    }
    public set stretchDirection(value: StretchDirection) {
        if (this._stretchDirection !== value) {
            this._stretchDirection = value;
            this._imageRender.stretchDirection = value;
        }
    }
    /**
     * 获取或设置垂直滚动位置
     */
    public get scrollVerticalOffset() {
        const parentElement = this.parentElement;
        if (parentElement && parentElement.tagName.toLowerCase() === 'div') {
            if (parentElement.style.overflowY === 'auto') {
                return parentElement.scrollTop;
            }
        }
        return 0;
    }
    public set scrollVerticalOffset(value: number) {
        const parentElement = this.parentElement;
        if (parentElement && parentElement.tagName.toLowerCase() === 'div') {
            parentElement.scrollTop = value;
        }
    }
    /**
     * 获取或设置水平滚动位置
     */
    public get scrollHorizontalOffset() {
        const parentElement = this.parentElement;
        if (parentElement && parentElement.tagName.toLowerCase() === 'div') {
            if (parentElement.style.overflowX === 'auto') {
                return parentElement.scrollLeft;
            }
        }
        return 0;
    }
    public set scrollHorizontalOffset(value: number) {
        const parentElement = this.parentElement;
        if (parentElement && parentElement.tagName.toLowerCase() === 'div') {
            parentElement.scrollLeft = value;
        }
    }
    //#endregion
    
    //#region 公共方法
    /**
     * client坐标点转换未canvas坐标点
     * @param point 
     */
    public clientPointToCanvasPoint (point: Point): Point {
        if (this._canvas) {
            const bbox = this._canvas.getBoundingClientRect();
            return new Point(Math.round(point.x - bbox.left), Math.round(point.y - bbox.top));
        }
        return point;
    }
    /**
     * 画布坐标点转换为图片坐标点
     * @param {any} point
     */
    public canvasPointToImagePoint(point: Point): Point {
        let x = point.x, y = point.y;
        const imageRect = this.getImagesRect();
        if (!imageRect.isEmpty()) {
            x -= imageRect.x;
            y -= imageRect.y;
            x = x / this.imageScaleX;
            y = y / this.imageScaleY;
        }
        
        return { x: x, y: y };
    }
    /**
     * 图片坐标点转换画布坐标点
     * @param {any} point
     */
    public imagePointToCanvasPoint(point: Point): Point {
        let x = point.x * this.imageScaleX, y = point.y * this.imageScaleY;
        const imageRect = this.getImagesRect();
        if (!imageRect.isEmpty()) {
            x += imageRect.x;
            y += imageRect.y;
        }
        
        return { x: x, y: y };
    }
    /**
     * 保存图片
     */
    public saveImage() {
        const canvas = this._canvas;
        const ctx = this.context;

        const retCanvas = document.createElement('canvas');
        const retCtx = retCanvas.getContext('2d');
        
        if (retCtx) {
            if (this._imageRender.isSingleImage) {
                // 计算区域
                const imageRect = this.getImagesRect();
                const strokeRect = this.getStrokesRect();
                retCanvas.width = Math.max(imageRect.width, strokeRect.width, this.parentWidth);
                retCanvas.height = Math.max(imageRect.height, strokeRect.height, this.parentHeight);
                // 填充背景
                retCtx.fillStyle = `${this._backgroundColor}`;
                retCtx.fillRect(0, 0, retCanvas.width, retCanvas.height);
                // 计算坐标偏移
                const minX = Math.min(imageRect.x, strokeRect.x);
                const minY = Math.min(imageRect.y, strokeRect.y);
                retCtx.translate(-minX, -minY);
                // 绘制图片
                this._imageRender.render(retCtx);
                // 绘制元素

                // 绘制画笔
                this.drawStrokes(retCtx);
            } else {
                retCanvas.width = canvas.width;
                retCanvas.height = canvas.height;
                retCtx.drawImage(canvas, 0, 0, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height);
            }
            const imgdata = retCanvas.toDataURL('image/jpeg', 0.5);
            const a = document.createElement('a');
            a.href = imgdata;
            a.download = '下载.jpg';
            a.click();
        }
    }
    /**
     * 获取所有线条的呈现区域
     */
    public getStrokesRect(): Rect {
        let rect = Rect.Empty;
        const strokes = this._strokes;
        if (strokes && strokes.length) {
            strokes.forEach((stroke) => {
                const strokeRect = stroke.bounds;
                rect = rect.union(strokeRect);
            });
        }
        return rect;
    }
    /**
     * 获取底图图片呈现区域
     */
    public getImagesRect(): Rect {
        return this._imageRender.bounds;
    }
    /**
     * 获取html内容呈现区域
     */
    public getHtmlRect(): Rect {
        return this._htmlTextRender.bounds;
    }
    /**
     * 获取元素呈现区域
     */
    public getElementsRect() {
        return Rect.Empty;
    }
    /**
     * 清除所有线条
     */
    public clearStrokes() {
        if (this._strokes && this._strokes.length > 0) {
            const oldStrokes = this.strokes;
            if (oldStrokes && oldStrokes.length > 0) {
                this._uodoItems.push(new UndoItem(oldStrokes));
            }
            this._strokes = [];
            this.reDraw();
        }
    }
    /**
     * 清除所有元素
     */
    public clearElements() {
        if (this._elements && this._elements.length > 0) {
            //清除元素
            this._elements = [];
            this.reDraw();
        }
    }
    /**
     * 重绘画板内容
     */
    public reDraw() {
        //刷新画布高度
        this.refreshCanvasHeight();
        //刷新滚动条状态
        this.refreshScrollState();
        // 清空画布绘制内容
        this.clearCurrentDrawing();
        // 绘制背景
        this.drawBackgroundColor();
        // 绘制图片
        this.drawImages();
        //绘制html内容
        this.drawHtml();
        //绘制元素
        this.drawElements();
        //绘制线条
        this.drawStrokes(this.context);
    }
    /**
     * 强制刷新（图片、html内容等呈现区域）并重绘
     */
    public updateLayout() {
        let newStrokes: Stroke[] | null = null;
        const _callback = () => {
            // 恢复图像线条为canvas线条
            if (newStrokes && newStrokes.length > 0) {
                this._strokes = this.imageStrokesToCanvasStrokes(newStrokes);
            }
            // 重新绘制
            this.reDraw();
        };
        if (this._imageRender.existImage || this._htmlTextRender.existHtml) {
                if (this._imageRender.existImage) {
                    // 保存线条为图上线条
                    newStrokes = this.canvasStrokesToImageStrokes(this._strokes);
                    this._imageRender.refreshImagesRenderBounds(() => {
                        if (this._htmlTextRender.existHtml) {
                            this._htmlTextRender.refreshHtmlRenderBounds(() => {
                                _callback();
                            });
                        } else {
                            _callback();
                        }
                    });
                } else if (this._htmlTextRender.existHtml) {
                    this._htmlTextRender.refreshHtmlRenderBounds(() => {
                        _callback();
                    });
                }
        } else {
            _callback();
        }
    }
    /**
     * 设置为自动滚动条
     */
    public autoScroll() {
        const parentElement = this.parentElement;
        if (parentElement && parentElement.tagName.toLowerCase() === 'div') {
            parentElement.style.overflowY = 'auto';
        }
    }
    /**
     * 禁用滚动条
     */
    public disableScroll() {
        const parentElement = this.parentElement;
        if (parentElement && parentElement.tagName.toLowerCase() === 'div') {
            parentElement.style.overflowY = 'hidden';
        }
    }
    /**
     * 绘制线段
     * @param p1 线段起点坐标
     * @param p2 线段终点坐标
     * @param lineWidth 线段粗细，如果为空则取当前画板的设置粗细
     * @param lineColor 线段颜色，如果为空则取当前画板的设置颜色
     * @param ctx 绘制上下文
     */
    public drawLine(p1: StrokePoint, p2: StrokePoint, lineWidth?: number, lineColor?: string, ctx?: CanvasRenderingContext2D) {
        ctx = ctx || this.context;
        if (ctx) {
            ctx.lineJoin = 'round';
            ctx.lineCap = 'round';
            ctx.strokeStyle = typeof(lineColor) === 'undefined' ? this.strokeColor : lineColor;
            ctx.lineWidth = typeof(lineWidth) === 'undefined' ? this.strokeWidth : lineWidth;
            ctx.save();
            ctx.beginPath();
            ctx.moveTo(p1.x, p1.y);
            ctx.lineTo(p2.x, p2.y);
            ctx.stroke();
            ctx.restore();
        }
    }
    /**
     * 新建（添加）一个线条
     * @param lineId 线条id
     * @param lineWidth 线条粗细
     * @param lineColor 线条颜色
     * @param points 线条初始点集合
     */
    public addStroke(lineId: string, lineWidth: number, lineColor: string, points: StrokePoint[] = []): Stroke {
        lineColor = typeof(lineColor) === 'undefined' ? this.strokeColor : lineColor;
        lineWidth = typeof(lineWidth) === 'undefined' ? this.strokeWidth : lineWidth;
        const stroke = new Stroke(lineId, lineWidth, lineColor);
        if (stroke && points && points.length > 0) {
            stroke.addPoints(points);
        }
        this.pushStroke(stroke);
        return stroke;
    }
    /**
     * 添加一个新的线条
     * @param stroke 新的线条
     */
    public pushStroke(stroke: Stroke | Stroke[]) {
        if (stroke) {
            if (stroke instanceof Stroke) {
                this._strokes.push(stroke);
            } else if (stroke instanceof Array) {
                this._strokes.push(...stroke);
            }
        }
    }
    /**
     *  移除最后一根绘制的线条(撤销)
     */
    public strokeUndo() {
        let stroke: Stroke | null = null;
        const strokes = this._strokes;
        if (strokes && strokes.length > 0) {
            const temp =  strokes.pop();
            stroke = temp ? temp : null;
            if (stroke) {
                this._uodoItems.push(new UndoItem([stroke]));
            }
            //重绘
            this.reDraw();
        }
        return stroke;
    }
    /**
     * 恢复删除的线条(重做)
     */
    public strokeRedo() {
        const uodoItems = this._uodoItems;
        if (uodoItems && uodoItems.length > 0) {
            const temp =  uodoItems.pop();
            if (temp) {
                const strokes = temp.strokes;
                if (strokes && strokes.length) {
                    // 加入线条集合
                    this.pushStroke(strokes);

                    // 重绘
                    this.reDraw();
                }
            }
        }
    }
    /**
     * 旋转图片
     * @param imgIndex 
     * @param angle 
     */
    public imageRotate(imgIndex = 0, angle: number) {
        this._imageRender.imageRotate(imgIndex, angle, () => this.updateLayout());
    }
    /**
     * 缩小图片
     * @param imgIndex 
     */
    public imageScaleIn(imgIndex = 0) {
        this.imageScale(imgIndex);
    }
    /**
     * 放大图片
     * @param imgIndex 
     */
    public imageScaleOut(imgIndex = 0) {
        this.imageScale(imgIndex, 'scale_out');
    }
    /**
     * 提高图片亮度
     * @param imgIndex 
     */
    public brightLightUp(imgIndex = 0) {
        this._imageRender.brightLightUp(imgIndex, () => this.reDraw());
    }
    /**
     * 降低图片亮度
     * @param imgIndex 
     */
    public brightLightDown(imgIndex = 0) {
        this._imageRender.brightLightDown(imgIndex, () => this.reDraw());
    }
    /**
     * 将canvas线条转换为图片线条
     * @param strokes 
     */
    public canvasStrokesToImageStrokes(strokes: Stroke[]) {
        const newStrokes: Stroke[] = [];
        if (strokes && strokes.length > 0) {
            strokes.forEach((stroke) => {
                const newStroke = new Stroke(stroke.strokeId, stroke.strokeWidth, stroke.strokeColor);
                newStrokes.push(newStroke);
                stroke.points.forEach((point) => {
                    const imagePoint = this.canvasPointToImagePoint(point);
                    newStroke.addPoint(imagePoint.x, imagePoint.y, point.factor);
                });
            });
        }
        return newStrokes;
    }
    /**
     * 将图片线条转换为canvas线条
     * @param strokes 
     */
    public imageStrokesToCanvasStrokes(strokes: Stroke[]) {
        const newStrokes: Stroke[] = [];
        if (strokes && strokes.length > 0) {
            strokes.forEach((stroke) => {
                const newStroke = new Stroke(stroke.strokeId, stroke.strokeWidth, stroke.strokeColor);
                newStrokes.push(newStroke);
                stroke.points.forEach((point) => {
                    const canvasPoint = this.imagePointToCanvasPoint(point);
                    newStroke.addPoint(canvasPoint.x, canvasPoint.y, point.factor);
                });
            });
        }
        return newStrokes;
    }
    /**
     * 清除所有绘制内容
     */
    public clearCurrentDrawing() {
        const ctx = this.context;
        if (ctx) {
            ctx.clearRect(0, 0, this.width, this.height);
        }
    }
    /**
     * 判断加载成功的是否为单张图片
     */
    public isSingleImage() {
        return this._imageRender.isSingleImage;
    }
    /**
     * 判断加载成功的是否为多张图片
     */
    public isMutipleImage() {
        return this._imageRender.isMutipleImage;
    }
    /**
     * 判断是否存在加载成功的html
     */
    public existHtml() {
        return this._htmlTextRender.existHtml;
    }
    //#endregion

    //#region 私有方法
    /**
     * 绘制线条集合
     * @param ctx 
     */
    private drawStrokes(ctx: CanvasRenderingContext2D) {
        const strokes  = this._strokes;
        if (strokes && strokes.length > 0) {
            strokes.forEach((stroke) => {
                this.drawStroke(ctx, stroke);
            });
        }
    }
    /**
     * 绘制线条
     * @param ctx 绘制上下文
     * @param stroke 待绘制的线条
     */
    private drawStroke(ctx: CanvasRenderingContext2D, stroke: Stroke) {
        if (stroke) {
            const points = stroke.points;
            if (points && points.length > 0) {
                let lastPoint: StrokePoint;
                points.forEach((point, index) => {
                    if (index === 0) {
                        lastPoint = point;
                    } else {
                        this.drawLine(lastPoint, point, stroke.strokeWidth, stroke.strokeColor, ctx);
                        lastPoint = point;
                    }
                });
            }
        }
    }
    /**
     * 绘制图片
     * @param images 
     */
    private drawImages() {
        if (this._imageRender.existImage) {
            this._imageRender.render(this.context);
        }
    }
    /**绘制html内容 */
    private drawHtml() {
        if (!this._imageRender.existImage) {
            this._htmlTextRender.render(this.context);
        }
    }
    /**
     * 绘制元素
     */
    private drawElements() {

    }
    /**绘制背景色 */
    private drawBackgroundColor() {
        const ctx = this.context;
        if (ctx) {
            // 绘制背景
            ctx.fillStyle = this.backgroundColor || '#FFF';
            ctx.fillRect(0, 0, this.width, this.height);
        }
    }
    /**
     * 鼠标或触控按下
     * @param event 
     */
    private mouseOrTouchStartEvent(event: MouseEvent | TouchEvent) {
        if (event) {
            // 仅识别鼠标左键
            if (event instanceof MouseEvent && (event as MouseEvent).button !== 0) {
                event.preventDefault();
                event.stopImmediatePropagation();
                return;
            }
            if (this.mode  === CanvasMode.Ink) {
                this._inkProcessor.active(event);
            } else if (this.mode  === CanvasMode.Eraser) {
                this._eraserProcessor.active(event);
            } else if (this.mode  === CanvasMode.Select) {
                this._inkProcessor.active(event);
            }
        }
    }
    /**
     * 刷新画布高度
     */
    private refreshCanvasHeight() {
        const imageNeedSize = Size.Empty, htmlNeedSize = Size.Empty, elementNeedSize = Size.Empty, strokeNeedSize = Size.Empty;
        const strokeRect = this.getStrokesRect();
        const imagesRect = this.getImagesRect();
        const elementsRect = this.getElementsRect();
        const htmlRect = this._htmlTextRender.bounds;
        // 底图图片需要的高度
        if (imagesRect && !imagesRect.isEmpty()) {
            imageNeedSize.width = imagesRect.x + imagesRect.width;
            imageNeedSize.height = imagesRect.y + imagesRect.height;
        }
        // html内容需要的高度
        if (imageNeedSize.isEmpty() && htmlRect && !htmlRect.isEmpty()) {
            htmlNeedSize.width = htmlRect.x + htmlRect.width;
            htmlNeedSize.height = htmlRect.y + htmlRect.height;
        }
        // 元素呈现需要的高度
        if (elementsRect && !elementsRect.isEmpty()) {
            elementNeedSize.width = elementsRect.x + elementsRect.width;
            elementNeedSize.height = elementsRect.y + elementsRect.height;
        }
        // 线条呈现需要的高度
        if (strokeRect && !strokeRect.isEmpty()) {
            strokeNeedSize.width = strokeRect.x + strokeRect.width;
            strokeNeedSize.height = strokeRect.y + strokeRect.height;
        }
        // 设置画布显示高度
        const parentWidth = this.parentWidth;
        const parentHeight = this.parentHeight;
        this.width = Math.max(imageNeedSize.width, htmlNeedSize.width, elementNeedSize.width, strokeNeedSize.width, parentWidth);
        this.height = Math.max(imageNeedSize.height, htmlNeedSize.height, elementNeedSize.height, strokeNeedSize.height, parentHeight);
    }
    /**
     * 刷新滚动条状态
     */
    private refreshScrollState() {
        // 如果只有一张图片则禁用滚动条
        if (this._imageRender.isSingleImage) {
            this.disableScroll();
            return;
        }
        // 根据高度来确定是否需要显示滚动条
        if (this.height > this.parentHeight) {
            this.autoScroll();
        } else {
            this.disableScroll();
        }
    }
    /**
     * 图片变化处理
     * @param imgIndex 
     * @param flag 
     */
    private imageScale(imgIndex: number, flag: 'scale_in' | 'scale_out' = 'scale_in') {
        if (!this._imageRender.isSingleImage) {
            return;
        }

        // 保存当前线条为图片线条
        const newStrokes = this.canvasStrokesToImageStrokes(this._strokes);
        const _callback = (_deltWidth: number, _deltHeight: number, _relateScale: number) => {
            // 变换书写内容
            this._strokes = this.imageStrokesToCanvasStrokes(newStrokes);

            // 重绘所有
            this.reDraw();

            // // 滚动到指定位置
            // if (this._imageRender.isMutipleImage) {
            //     this.scrollVerticalOffset += _deltHeight / 2;
            // }
        };
        if (flag === 'scale_in') {
            this._imageRender.imageScaleIn(imgIndex, _callback);
        } else if (flag === 'scale_out') {
            this._imageRender.imageScaleOut(imgIndex, _callback);
        }
    }
    /**
     * 检查画布事件订阅
     */
    private checkCanvasEvent() {
        if (this.needBindCanvasEvent()) {
            this.attachCanvasMouseAndTouchEvent();
        } else {
            this.deattachCanvasMouseAndTouchEvent();
        }
    }
    /**
     * 检查当前模式是否需要绑定鼠标和触控事件
     * @param value 要检查的模式，如果未传递此参数或此参数为空则取当前的模式
     */
    private needBindCanvasEvent(value?: CanvasMode) {
        value = typeof(value) === 'undefined' ? this.mode : value;
        return this.mode === CanvasMode.Ink || CanvasMode.Eraser || CanvasMode.Select;
    }
    //#endregion
    /**
     * 订阅画布鼠标和触控事件
     */
    private attachCanvasMouseAndTouchEvent() {
        // 确保只订阅一次事件
        this.deattachCanvasMouseAndTouchEvent();
        const canvas = this._canvas;
        if (canvas) {
            canvas.addEventListener('mousedown', this.onMouseOrTouchStart);
            canvas.addEventListener('touchstart', this.onMouseOrTouchStart);
        }
    }
    /**
     * 取消订阅画布鼠标和触控事件
     */
    private deattachCanvasMouseAndTouchEvent() {
        const canvas = this._canvas;
        if (canvas) {
            canvas.removeEventListener('mousedown',  this.onMouseOrTouchStart);
            canvas.removeEventListener('touchstart', this.onMouseOrTouchStart);
        }
    }
    
    //#endregion
}